/*
 * detect_param.cpp
 *
 *  Created on: 2016年6月11日
 *      Author: guyadong
 */
#include "detectface.h"
namespace gdface {
/*
 * 计算图像检测时每一级压缩尺寸，
 * 检测窗口比例从max_size_ratio到min_size_ratio按step步进缩小，
 * 根据每一级检测窗口尺寸与detect_win_size的比例计算出图像缩小的尺寸，
 * 如:src_size2048, detect_win_size=24,max_size_ratio=0.7f,min_size_ratio=0.3f,step=0.8f时返回的结果为:
 * {34,42,53,66,83,104,131,163,204,256,321,399,501,630,780,800}
 * src_size 原始尺寸(取图像的min(width,height))
 * detect_win_size 检测窗口缩放目标尺寸,为0时使用默认值
 * max_size_ratio 最大检测窗口尺寸与src_size中的比例,为0时使用默认值
 * min_size_ratio 最小检测窗口尺寸与src_size中的比例,为0时使用默认值
 * step 检测窗口步进缩小比例,为0时使用默认值
 * */
std::vector<float> get_scale_level(size_t src_size, size_t detect_win_size, float max_size_ratio,
		float min_size_ratio, float step) {
	throw_if(
			max_size_ratio < 0 || size_t(max_size_ratio * src_size) >= src_size || min_size_ratio < 0
					|| min_size_ratio >= 1 || step < 0 || step >= 1 || 0 == src_size)
	throw_if(src_size <= detect_win_size || max_size_ratio < min_size_ratio)
	if (0 == detect_win_size) {
		detect_win_size = DETECT_WIN_SIZE;
	}
	if (0.0f == max_size_ratio) {
		max_size_ratio = DEFAULT_MAX_DETECT_WIN_RATIO;
	}
	if (0.0f == min_size_ratio) {
		min_size_ratio = float(DEFAULT_MIN_DETECT_WIN_SIZE) / src_size;
	}
	if (0.0f == step) {
		step = 1/global_measure.step;
	}
	std::vector<float> level;
	auto scale_ratio = max_size_ratio;
	auto ratio = max_size_ratio;
	for (; ratio >= min_size_ratio; ratio *= step) {
		if (size_t(ratio * src_size) <= detect_win_size) {
			level.emplace_back(1.0f);
			break;
		}
		level.emplace_back(float(detect_win_size) / float(src_size) / ratio);
	}
	if (ratio < min_size_ratio) {
		level.emplace_back(float(detect_win_size) / float(src_size) / min_size_ratio);
	}
	return level;
}
/*
 * 计算图像检测时每一级压缩尺寸
 * src_size 原始尺寸(取图像的min(width,height))
 * detect_win_size 检测窗口目标尺寸,为0时使用默认值
 * max_size 最大检测窗口尺寸,为0时使用默认值
 * min_size 最小检测窗口尺寸,为0时使用默认值
 * step 检测窗口步进缩小比例,为0时使用默认值
 * */
std::vector<float> get_scale_level(size_t src_size, size_t detect_win_size, size_t max_size,
		size_t min_size, float step) {
	if (0 == max_size)
		max_size = size_t(src_size * DEFAULT_MAX_DETECT_WIN_RATIO);

	if (0 == min_size)
		min_size = DEFAULT_MIN_DETECT_WIN_SIZE;

	throw_if(src_size < max_size || max_size < min_size)
	return get_scale_level(src_size, detect_win_size, float(max_size) / src_size, float(min_size) / src_size, step);
}
 /*
  * 计算图像检测时每一级检测窗口尺寸，
  * 检测窗口比例从detect_range_floor到detect_range_upper按step步进放大，
  * 如:src_size2048, detect_win_size=24,detect_range_upper=0.7f,detect_range_floor=0.0f,step=1.1f时返回的结果为:
  * {39,43,47,52,57,63,69,76,83,92,101,111,122,134,147,162,178,196,215,237,260,286,315,347,381,419,461,507,558,614,675,742,816,898,988,1087,1195,1315}
  * detect_range_upper改为0.5f,detect_range_floor=0.1f时返回的结果为:
  * {196,215,237,260,286,315,347,381,419,461,507,558,614,675,742,816,898,988},是前面结果的子集
  * src_size 原始尺寸(取图像的min(width,height))
  * detect_win_size 最小检测窗口尺寸,为0时使用默认值
  * detect_range_upper 最大检测窗口尺寸与src_size中的比例,为0时使用默认值
  * detect_range_floor 最小检测窗口尺寸与src_size中的比例,为0时使用默认值
  * step 检测窗口步进放大比例,为0时使用默认值
  * */
scale_size_type get_detect_win_size_level(size_t src_size, size_t min_detect_win_size,
 		float detect_range_upper, float detect_range_floor, float step) {
 	throw_if(
 			detect_range_upper < 0 || detect_range_upper > 1 || detect_range_floor < 0 || detect_range_floor >= 1
 					|| (step <= 1 && 0 != step) || 0 == src_size)
 	throw_if(src_size <= min_detect_win_size || detect_range_upper < detect_range_floor)
 	if (0 == min_detect_win_size) {
 		min_detect_win_size = DETECT_WIN_SIZE;
 	}
 	if (0.0f == detect_range_upper) {
 		detect_range_upper = DEFAULT_MAX_DETECT_WIN_RATIO;
 	}
 	if (0.0f == detect_range_floor) {
 		detect_range_floor = float(DEFAULT_MIN_DETECT_WIN_SIZE) / src_size;
 	}
 	detect_range_floor = std::max<float>(detect_range_floor, float(min_detect_win_size) / src_size);
 	if (0.0f == step) {
 		step = DETECT_WIN_SCALE_RATIO;
 	}
 	scale_size_type level;
 	auto _pow_num = size_t(std::floor(std::log(detect_range_floor * src_size / DETECT_WIN_SIZE) / std::log(step)));
 	auto ratio = std::pow(float(step), _pow_num);
 	for (auto detect_win_size = size_t(DETECT_WIN_SIZE * ratio + DETECT_WIN_SCALE_COMP), max_detect_size = size_t(
 			detect_range_upper * src_size + DETECT_WIN_SCALE_COMP); detect_win_size <= max_detect_size;
 			ratio *= step, detect_win_size = size_t(DETECT_WIN_SIZE * ratio + DETECT_WIN_SCALE_COMP)) {
 		level.emplace_back(detect_win_size);
 	}
 	return level;
}
 /*
  * 计算图像检测时每一级检测窗口尺寸，
  * src_size 原始尺寸(取图像的min(width,height))
  * detect_win_size 最小检测窗口尺寸,为0时使用默认值
  * detect_range_upper 最大检测窗口尺寸,为0时使用默认值
  * detect_range_floor 最小检测窗口尺寸,为0时使用默认值
  * step 检测窗口步进放大比例,为0时使用默认值
  * */
scale_size_type get_detect_win_size_level(size_t src_size, size_t min_detect_win_size,
 		size_t detect_range_upper, size_t detect_range_floor, float step) {
 	if (0 != detect_range_floor && detect_range_floor < DETECT_WIN_SIZE)
 		detect_range_floor = DETECT_WIN_SIZE;

 	if (0 == detect_range_upper)
 		detect_range_upper = size_t(src_size * DEFAULT_MAX_DETECT_WIN_RATIO);
 	else if (detect_range_upper > src_size)
 		detect_range_upper = src_size;

 	return get_detect_win_size_level(src_size, min_detect_win_size, float(detect_range_upper) / src_size,
 			float(detect_range_floor) / src_size, step);
}
 /*
  * 计算图像检测时每一级检测窗口尺寸，
  * src_size 原始尺寸(取图像的min(width,height))
  * detect_range_upper 最大检测窗口尺寸,为0时使用默认值
  * detect_range_floor 最小检测窗口尺寸,为0时使用默认值
  * */
scale_index_type get_detect_win_size_index(size_t src_size, size_t detect_range_upper,
 		size_t detect_range_floor) {
 	if (!detect_range_floor)
 		detect_range_floor = DEFAULT_MIN_DETECT_WIN_SIZE;
 	else if (detect_range_floor < DETECT_WIN_SIZE)
 		detect_range_floor = DETECT_WIN_SIZE;

 	if (0 == detect_range_upper)
 		detect_range_upper = size_t(src_size * DEFAULT_MAX_DETECT_WIN_RATIO);
 	else if (detect_range_upper > src_size)
 		detect_range_upper = src_size;

 	throw_if(detect_range_upper < detect_range_floor)
 	auto floor_index = global_measure.index_of_measure_floor(detect_range_floor);
 	auto upper_index = global_measure.index_of_measure_ceil(detect_range_upper);
 	return scale_index_type { upper_index, floor_index };
}
 /*
  * 计算图像检测时每一级检测窗口尺寸基于global_measure.detect_win_size的下标，
  * src_size 原始尺寸(取图像的min(width,height))
  * detect_range_upper 最大检测窗口尺寸与src_size中的比例,为0时使用默认值
  * detect_range_floor 最小检测窗口尺寸与src_size中的比例,为0时使用默认值
  * */
scale_index_type get_detect_win_size_index(size_t src_size, float detect_range_upper,
 		float detect_range_floor) {
 	throw_if(
 			detect_range_upper < 0 || detect_range_upper > 1 || detect_range_floor < 0 || detect_range_floor >= 1
 					|| 0 == src_size)
 	throw_if(src_size <= DETECT_WIN_SIZE || detect_range_upper < detect_range_floor)
 	if (0.0f == detect_range_upper) {
 		detect_range_upper = DEFAULT_MAX_DETECT_WIN_RATIO;
 	}
 	if (0.0f == detect_range_floor) {
 		detect_range_floor = float(DEFAULT_MIN_DETECT_WIN_SIZE) / src_size;
 	}
 	return get_detect_win_size_index(src_size, size_t(detect_range_upper * src_size),
 			std::max<size_t>(size_t(detect_range_floor * src_size), DETECT_WIN_SIZE));
}
void detect_param_builder::clean_i(){param.detect_range_i={-1,-1};}
void detect_param_builder::clean_f(){param.detect_range_f={-1.0f,-1.0f};}
detect_param_builder& detect_param_builder::set_detect_win_scale_level(size_t s) {
	throw_if(s >= global_measure.detect_win_size.size())
	param.detect_scale_level = s;
	param.detect_win_size = global_measure.detect_win_size[param.detect_scale_level];
	return *this;
}

detect_param_builder& detect_param_builder::set_max_size_ratio(float ratio) {
	param.detect_range_f.s0 = ratio;
	clean_i();
	return *this;
}

detect_param_builder& detect_param_builder::set_min_size_ratio(float ratio) {
	param.detect_range_f.s1 = ratio;
	clean_i();
	return *this;
}

detect_param_builder& detect_param_builder::set_detect_range(const gf_float2& range) {
	param.detect_range_f = range;
	clean_i();
	return *this;
}

//detect_param_builder& detect_param_builder::set_step(float ratio) {
//	param.step = ratio;
//	return *this;
//}

detect_param_builder& detect_param_builder::set_detect_range(const gf_int2& range) {
	param.detect_range_i = range;
	clean_f();
	return *this;
}

detect_param_builder& detect_param_builder::set_max_size(int size) {
	param.detect_range_i.s0 = size;
	clean_f();
	return *this;
}

detect_param_builder& detect_param_builder::set_min_size(int size) {
	param.detect_range_i.s1 = size;
	clean_f();
	return *this;
}

detect_param_builder& detect_param_builder::set_min_first(bool min_first) {
	param.min_first = min_first;
	return *this;
}

detect_param_builder& detect_param_builder::set_detect_win_shrink_floor(size_t shrink_floor) {
	param.detect_win_shrink_floor = shrink_floor;
	return *this;
}
detect_param detect_param_builder::build(){
	return param;
}

scale_size_type build_detect_size(const detect_param&param,size_t img_size) {
 	if (param.detect_range_i.s0 >= 0 && param.detect_range_i.s1 >= 0) {
 		return get_detect_win_size_level(img_size, param.detect_win_size, size_t(param.detect_range_i.s0),
 				size_t(param.detect_range_i.s1), 1/global_measure.step);
 	} else if (param.detect_range_f.s0 >= 0 && param.detect_range_f.s1 >= 0)
 		return get_detect_win_size_level(img_size, param.detect_win_size, param.detect_range_f.s0, param.detect_range_f.s1, 1 / global_measure.step);
 	throw face_exception(SOURCE_AT, "invalid detect range");
}

scale_index_type build_detect_index(const detect_param&param,size_t img_size) {
 	if (param.detect_range_i.s0 >= 0 && param.detect_range_i.s1 >= 0) {
 		return get_detect_win_size_index(img_size, size_t(param.detect_range_i.s0), size_t(param.detect_range_i.s1));
 	} else if (param.detect_range_f.s0 >= 0 && param.detect_range_f.s1 >= 0)
 		return get_detect_win_size_index(img_size, param.detect_range_f.s0, param.detect_range_f.s1);

 	throw face_exception(SOURCE_AT, "invalid detect range");
}
}/* namespace gdface */



